package com.shyroke.daydayzhuansvc.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.querydsl.core.QueryResults;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.shyroke.daydayzhuanapi.constant.RedisKeyPrefix;
import com.shyroke.daydayzhuanapi.dto.*;
import com.shyroke.daydayzhuanapi.entity.*;
import com.shyroke.daydayzhuanapi.mapper.SubjectMapper;
import com.shyroke.daydayzhuandao.respository.SubjectAppRepository;
import com.shyroke.daydayzhuandao.respository.SubjectRepository;
import com.shyroke.daydayzhuansvc.util.*;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class SubjectService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private SubjectRepository subjectRepository;
    @Autowired
    private SubjectAppRepository subjectAppRepository;
    @Autowired
    private JPAQueryFactory factory;
    @Autowired
    private SubjectMapper subjectMapper;
    @Autowired
    private OSSService ossService;
    @Autowired
    private RedisTemplate redisTemplate;

    public TabelData<SubjectAdminDto> page(Page page, SubjectAdminRequest request) {
        QSubjectEntity qSubjectEntity = QSubjectEntity.subjectEntity;
        JPAQuery<SubjectEntity> query = factory.selectFrom(qSubjectEntity);
        if(StrUtil.isNotBlank(request.getTitle())){
            query = query.where(qSubjectEntity.title.like("%"+request.getTitle()+"%"));
        }
        QueryResults<SubjectEntity> queryResults = query
                .offset(PageRequest.of(page.getPage() - 1, page.getLimit()).getOffset()).limit(page.getLimit())
                .orderBy(qSubjectEntity.isShow.desc(),qSubjectEntity.id.desc())
                .fetchResults();

        List<SubjectAdminDto> list = queryResults.getResults().stream().map(e -> subjectMapper.entityToAdminDto(e)).collect(Collectors.toList());

        return new TabelData(list,(int)queryResults.getTotal());
    }

    public void save(SubjectAddRequest request,Integer userId) {
        SubjectEntity subjectEntity = subjectMapper.addRequestToEntity(request);
        subjectEntity.setCreateId(userId);
        subjectEntity.setIsShow(true);
        subjectEntity.setUpdateTime(new Date());
        subjectEntity.setCreateTime(new Date());
        subjectEntity.setReadMount(0);
        subjectRepository.save(subjectEntity);

        if(CollectionUtil.isEmpty(request.getAppIds())){
            return;
        }
        List<SubjectAppEntity> subjectAppEntityList = request.getAppIds().stream().map(appId -> {
            SubjectAppEntity e = new SubjectAppEntity();
            AppEntity appEntity = new AppEntity();
            appEntity.setId(appId);
            e.setSubjectEntity(subjectEntity);
            e.setAppEntity(appEntity);
            return e;
        }).collect(Collectors.toList());
        subjectAppRepository.saveAll(subjectAppEntityList);

    }

    public void offline(Integer id, Boolean isShow) {
        Optional<SubjectEntity> optionalSubject = subjectRepository.findById(id);
        if (optionalSubject.isPresent()) {
            SubjectEntity subjectEntity = optionalSubject.get();
            subjectEntity.setUpdateTime(new Date());
            subjectEntity.setIsShow(isShow);
            subjectRepository.save(subjectEntity);
        }
    }

    public void update(SubjectAddRequest request) throws Exception{
        Optional<SubjectEntity> optionalSubject = subjectRepository.findById(request.getId());
        if (!optionalSubject.isPresent()) {
            return;
        }
        SubjectEntity subject = optionalSubject.get();
        subject.setUpdateTime(new Date());
        //防止图片地址的字符被转义，比如a(1).png会被转义成a%281%29.png,导致显示错误。
        if(StrUtil.isNotBlank(request.getCover())){
            String url = CommonUtil.deleteOSSImgPre(request.getCover());
            String url2 = URLDecoder.decode(url, "utf-8");
            subject.setCover(url2);
        }
        subjectMapper.updateDtoToEntity(request,subject);
        subjectRepository.save(subject);

        List<SubjectAppEntity> subjectAppList = subjectAppRepository.findBySubjectId(request.getId());
        subjectAppRepository.deleteAll(subjectAppList);

        List<SubjectAppEntity> subjectAppEntityList = request.getAppIds().stream().map(appId -> {
            SubjectAppEntity e = new SubjectAppEntity();
            AppEntity appEntity = new AppEntity();
            appEntity.setId(appId);
            e.setSubjectEntity(subject);
            e.setAppEntity(appEntity);
            return e;
        }).collect(Collectors.toList());
        subjectAppRepository.saveAll(subjectAppEntityList);

    }

    public TabelData<SubjectDto> homePage(Page page) {
        QSubjectEntity qSubjectEntity = QSubjectEntity.subjectEntity;
        QueryResults<SubjectEntity> queryResults = factory.selectFrom(qSubjectEntity).where(qSubjectEntity.isShow.eq(true))
                .offset(PageRequest.of(page.getPage() - 1, page.getLimit()).getOffset()).limit(page.getLimit())
                .orderBy(qSubjectEntity.isCommented.desc(),qSubjectEntity.id.desc())
                .fetchResults();

        List<SubjectDto> list = queryResults.getResults().stream().map(e -> subjectMapper.entityToDto(e)).collect(Collectors.toList());
        list.stream().forEach(dto ->{
            if(!StringUtils.isEmpty(dto.getCover())){
                if(!dto.getCover().startsWith("https://") && !dto.getCover().startsWith("http://")){
                    dto.setCover(CommonUtil.deleteOSSImgSuff(ossService.getImgUrl(dto.getCover())));
                }else{
                    dto.setCover(CommonUtil.deleteOSSImgSuff(dto.getCover()));
                }
            }
            List<AppDto> appList = dto.getAppList();
            appList.stream().forEach(app->{
                if(!StringUtils.isEmpty(app.getCover())){
                    if(!app.getCover().startsWith("https://") && !app.getCover().startsWith("http://")){
                        app.setCover(CommonUtil.deleteOSSImgSuff(ossService.getImgUrl(app.getCover())));
                    }else{
                        app.setCover(CommonUtil.deleteOSSImgSuff(app.getCover()));
                    }
                }
            });
        });
        return new TabelData<>(list,(int)queryResults.getTotal());
    }

    public void updateReadAmount(HttpServletRequest request, Integer subjectId) {
        String ip = IPUtil.getIpAddr(request);
        logger.info("访问IP："+ip);
        ip = ip.replaceAll(":",".");
        String key = RedisKeyPrefix.SUBJECTVIEW+":isViewd:"+subjectId+":"+ip;
        Set keys = redisTemplate.keys(key);
        if(CollectionUtils.isEmpty(keys)){
            String viewKey = RedisKeyPrefix.SUBJECTVIEW+":isViewd:"+subjectId+":"+ip;
            redisTemplate.opsForValue().set(viewKey,null);
            redisTemplate.expire(viewKey,7, TimeUnit.DAYS);
            //说明该IP没有浏览过,在redis里给该文章流量数+1
            this.setCount(subjectId);
        }
    }

    private void setCount(Integer subjectId) {
        String key = RedisKeyPrefix.SUBJECTCOUNT+":viewCount:"+subjectId;
        Object countObj = redisTemplate.opsForValue().get(key);
        if(countObj == null){
            redisTemplate.opsForValue().set(key,1);
            redisTemplate.expire(key,7, TimeUnit.DAYS);
        }else{
            int count = (Integer)countObj;
            redisTemplate.opsForValue().set(key,++count);
        }
    }

    public SubjectHomeDto findById(Integer subjectId) {
        Optional<SubjectEntity> optionalSubject = subjectRepository.findById(subjectId);
        if (!optionalSubject.isPresent()) {
            return null;
        }
        SubjectEntity subject = optionalSubject.get();
        SubjectHomeDto dto = subjectMapper.entityToHomeDto(subject);
        dto.getAppList().stream().forEach(app->{
            if(!StringUtils.isEmpty(app.getCover())){
                app.setCover(ossService.getImgUrl(app.getCover()));
            }
        });
        if(!StringUtils.isEmpty(dto.getCover())){
            dto.setCover(ossService.getImgUrl(dto.getCover()));
        }
        return dto;
    }

    public List<SubjectAdminDto> all() {
        List<SubjectEntity> list = subjectRepository.findAllByIsShowIsTrueOrderByIdDesc();
        return list.stream().map(e -> subjectMapper.entityToAdminDto(e)).collect(Collectors.toList());
    }

    public SubjectDto findNoContentById(Integer subjectId) {
        QSubjectEntity qSubjectEntity = QSubjectEntity.subjectEntity;
        return factory.select(Projections.bean(SubjectDto.class, qSubjectEntity.id, qSubjectEntity.title)).from(qSubjectEntity)
                .where(qSubjectEntity.isShow.eq(true), qSubjectEntity.id.eq(subjectId))
                .fetchOne();
    }

    public void updateCount(Integer subjectId) {
        subjectRepository.updateCount(subjectId);
    }

    public void commented(Integer id, Boolean isCommented) {
        Optional<SubjectEntity> optionalSubject = subjectRepository.findById(id);
        if (optionalSubject.isPresent()) {
            SubjectEntity subjectEntity = optionalSubject.get();
            subjectEntity.setUpdateTime(new Date());
            subjectEntity.setIsCommented(isCommented?"1":"0");
            subjectRepository.save(subjectEntity);
        }
    }
}
